///////////////////////////////////////////////////////////
///////////////// Have an itch? Scratch it! ///////////////
///////////////////////// SCRATCH /////////////////////////
/////////////////////  A MUD  Server   ////////////////////
///////////////////// By: Jared Devall ////////////////////
/////////////////////      Thanks:     ////////////////////
/////////////////////  DIKU/Merc/ROM   ////////////////////
///////////////////// Aetas/Deus Gang  ////////////////////
/////////////////////       Beej       ////////////////////
///////////////////////////////////////////////////////////

#include <list>
#include "definitions.h"
#include "commands.h"
#include "commandTable.h"
#include "character.h"
#include "world.h"
#include "stringutil.h"
#include "split.h"
#include "timestamp.h"

using namespace std;

// aCommand definitions
// (Keep in alphabetical order... it's MUCH easier)
aCmdCommands::aCmdCommands( ) {
	SetName( "commands" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdCommands::Execute( Character* c, const string &args ) {
	std::string buf;
	std::string temp;
	list< Command* >::iterator it;
	int f = 0;

	if ( c->getLevel() >= HEAD ) {
		buf << "\n\r\t{chead (level " << HEAD << ") commands:{x\n\r";
		for ( it = aCommandTable::Instance()._commands.begin(); it != aCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == HEAD ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	if ( c->getLevel() >= GOD ) {
		buf << "\n\r\t{cgod (level " << GOD << ") commands:{x\n\r";
		for ( it = aCommandTable::Instance()._commands.begin(); it != aCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == GOD ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	if ( c->getLevel() >= BUILDER ) {
		buf << "\n\r\t{cbuilder (level " << BUILDER << ") commands:{x\n\r";
		for ( it = aCommandTable::Instance()._commands.begin(); it != aCommandTable::Instance()._commands.end(); ++it ) {
			if ( (*it)->_level == BUILDER ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
			    f++;
			    if ( f == 5 ) {
					buf << "\n\r";
					f = 0;
				}
			}
		}
	}
	f = 0;
	buf << "\n\r\t{c-- Commands --{x \n\r";
	for ( it = aCommandTable::Instance()._commands.begin(); it != aCommandTable::Instance()._commands.end(); ++it ) {
		if ( (*it)->_level == 1 ) {
				if ( !(*it)->_enabled )
					buf << "{w";
				if ( f == 0 ) {
					buf << "  " << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				} else {
					buf << (*it)->_name.c_str() << spaces( 12, (*it)->_name.c_str(), temp );
				}
				if ( !(*it)->_enabled )
					buf << "{x";
		    f++;
		    if ( f == 5 ) {
				buf << "\n\r";
				f = 0;
			}
		}
	}


	c->Send( buf );

	return true;
}


aCmdExit::aCmdExit() {
	SetName( "exit" );
	SetLevel( 1 );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdExit::Execute( Character* c, const string& args ) {
	c->SetStatus( CONNECTED );
	c->Send( "You've been set to regular command mode.\n\r" );
	World::Instance().Omninet( c->getName() + " has left aedit mode.", STANDARD, c, false );
	return true;
}

aCmdKeyword::aCmdKeyword() {
	SetName( "keyword" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdKeyword::Execute( Character* c, const string& args ) {
	std::string buf;

	if ( args.empty() ) {
		c->Send( " >> \"keyword\" changes the keyword of the currently selected area.\n\r\n\rsyntax: keyword <value>\n\r" );
		return true;
	}
	if ( c->getArea() == 0 ) {
		c->Send( "You haven't selected an area.\n\r" );
		return true;
	}

	c->getArea()->SetKeyword( args.c_str() );
	buf << "The keyword of area " << c->getArea()->GetNumber() << " changed to \"" << args << "\".\n\r";

	c->Send( buf );
	return true;
}

aCmdList::aCmdList() {
	SetName( "list" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdList::Execute( Character* c, const string& args ) {
	Area* area = 0;
	std::list< Area* >::iterator it;
	std::string buf;

	c->Send( "\t{x--Area List--\n\r" );
	c->Send( " {wnumber  {Ykeyword                  {Cname{x\n\r" );
	c->Send( "   {RSize    {x[ {mRange         {x]   {Wpermissions{x\n\r" );
	c->Send( " {x-----------------------------------------------------\n\r" );
	for ( it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); it++ ) {
		area = (*it);
		buf.clear();
		c->Send( " {w%-8d{x", area->GetNumber() );
		c->Send( "{Y%-25s{x", area->GetKeyword() );
		c->Send( "{C%-40s{x", area->GetName() );
		c->Send( "\n\r   {R%-8d{x", area->GetSize() );
		c->Send( "[ {m%-5d{x", area->GetFirstv() );
		c->Send( " - {m%-5d{x ]", area->GetLastv() );
		if ( area->getPermissions().size() == 0 )
			buf << "none";
		else
			for ( std::list< int >::iterator it = area->getPermissions().begin(); it != area->getPermissions().end(); it++ )
				buf << (*it) << ' ';
		c->Send( "   {W%-20s{x", buf.c_str() );
		c->Send( "\n\r{x-----------------------------------------------------\n\r" );
	}
	return true;
}

aCmdMake::aCmdMake() {
	SetName( "make" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( true );
}

bool aCmdMake::Execute( Character* c, const string& args ) {
	Area* area = 0;
	std::list< Area* >::iterator it;
	std::string keyword;
	std::string buf1;
	std::string buf2;
	std::string error;
	std::string file = "system/areas/";
	int start;
	int size;
	int end;
	bool collision = false;

	split( args, keyword, buf1, buf2 );

	if ( keyword.empty() || buf1.empty() || buf2.empty() ) {
		c->Send( " >> \"make\" creates a new area and selects it.\n\r\n\rsyntax: make <keyword> <first vnum> <size>\n\r" );
		return true;
	}

	start = atoi( buf1.c_str() );
	size = atoi( buf2.c_str() );
	end = start + size - 1;

	// Make sure the size of the area is divisible by 25 (makes things look nicer, plus it's more stable)
	if ( size % 25 != 0 ) {
		c->Send( "The size of the area must be divisible by 25.\n\r" );
		return false;
	}

	// Check for vnum collisions...
	for ( it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); it++ ) {
		area = (*it);
		// Check starting point...
		if ( start >= area->GetFirstv() && start <= area->GetLastv() ) {
			collision = true;
			error = "You cannot start the area within the bounds of an existing area.\n\r";
		}
		// Check ending point...
		if ( end >= area->GetFirstv() && end <= area->GetLastv() ) {
			collision = true;
			error = "You cannot end the area within the bounds of an existing area.\n\r";
		}
		// Check for enveloping...
		if ( area->GetFirstv() >= start && area->GetLastv() <= end ) {
			collision = true;
			error = "You cannot create an area that encompasses an existing area.\n\r";
		}
	}

	if ( collision ) {
		c->Send( error );
		return false;
	}

	int num = World::Instance().getAreas().size();
	area = World::Instance().addArea();
	area->SetNumber( num );
	area->SetKeyword( keyword.c_str() );
	area->SetFirstv( start );
	area->SetLastv( end );
	area->SetSize( size );
	area->SetFile( ( file + keyword + ".area" ).c_str() );
	area->addPermission( c->getId() );
	c->setArea( area );

	return true;
}

aCmdName::aCmdName() {
	SetName( "name" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdName::Execute( Character* c, const string& args ) {
	std::string buf;

	if ( args.empty() ) {
		c->Send( " >> \"name\" changes the name of the currently selected area.\n\r\n\rsyntax: name <name>\n\r" );
		return true;
	}
	if ( c->getArea() == 0 ) {
		c->Send( "You haven't selected an area.\n\r" );
		return true;
	}

	c->getArea()->SetName( args.c_str() );
	buf << "The name of area " << c->getArea()->GetNumber() << " changed to \"" << args << "\".\n\r";

	c->Send( buf );
	return true;
}

aCmdPermissions::aCmdPermissions() {
	SetName( "permissions" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdPermissions::Execute( Character* c, const string& args ) {
	std::string buf;
	std::string action;
	std::string character;
	std::list< Character* >::iterator c_it;

	if ( c->getArea() == 0 ) {
		c->Send( "You haven't selected an area.\n\r" );
		return false;
	}

	if ( args.empty() ) {
		c->Send( "syntax: permissions add <name>\n\r        permissions remove <name>\n\r" );
		return false;
	}

	return false;
}

aCmdRemove::aCmdRemove() {
	SetName( "remove" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( true );
}

bool aCmdRemove::Execute( Character* c, const string& args ) {
	std::string buf;
	int number = atoi( args.c_str() );
	Area* area = 0;
	std::list< Area* >::iterator it;

	if ( args.empty() ) {
		c->Send( " >> \"remove\" deletes the given area.\n\r\n\rsyntax: remove <number>\n\r" );
		return false;
	}

	if ( c->getArea() == 0 ) {
		c->Send( "You haven't selected an area.\n\r" );
		return false;
	}

	area = c->getArea();
	World::Instance().getAreas().remove( area );
	delete area;
	area = 0;
	c->setArea( 0 );

	buf << "Area " << number << " deleted.\n\r";

	c->Send( buf );

	return true;
}

aCmdSelect::aCmdSelect() {
	SetName( "select" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdSelect::Execute( Character* c, const string& args ) {
	if ( args.empty() ) {
		c->Send( " >> \"select\" changes which area you're working on.\n\r\n\rsyntax: select <area number>\n\r" );
		return true;
	}
	std::string buf;
	std::string number;
	split( args, number, buf );

	// World::Instance().GetArea() will return first or last area upon bound error
	// Area #0 is uneditable by anyone. Period.
	Area* area = 0;
	if ( ( area = World::Instance().getArea( atoi( number.c_str() ) ) ) == NULL ) {
		c->Send( "That area doesn't exist.\n\r" );
		return false;
	}
	if ( area->GetNumber() > 0 ) {
		if ( area->getPermission( c->getId() ) || c->getLevel() >= HEAD ) {
			buf = "You've selected area #";
			buf << area->GetNumber() << ", \"" << area->GetName() << "\"\n\r";
			c->setArea( area );
		} else {
			buf << "You don't have permissions to that area.\n\r";
		}
	}
	else {
		buf = "That is not a valid area.\n\r";
		c->setArea( 0 );
	}

	c->Send( buf );
	return true;
}

aCmdView::aCmdView() {
	SetName( "view" );
	SetLevel( GOD );
	SetEnabled( true );
	SetOmniset( false );
}

bool aCmdView::Execute( Character* c, const string& args ) {
	std::string buf;
	Area* area = c->getArea();

	if ( area == 0 ) {
		c->Send( "You haven't selected an area.\n\r" );
		return false;
	}

	buf << "--------------------------------------------------\n\r";
	buf << "Number: {w" << area->GetNumber() << "\t{xName:  {C" << area->GetName() << "\n\r";
	buf << "{xSize:   {R" << area->GetSize() << "\t{xRange: {m" << area->GetFirstv() << " {x- {m" << area->GetLastv() << "\n\r";
	buf << "{xFile:   {y" << area->GetFile() << "{x\n\r";
	buf << "--------------------------------------------------\n\r";

	c->Send( buf );
	return true;
}
